package spl.army;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;

public class MissionHolder {
	private HashSet<Mission> missionSet = null;

	/**
	 * c'tor
	 */
	public MissionHolder() {
		this.missionSet = new HashSet<Mission>();
	}
	
	/**
	 * @return a copy of a missionList
	 */
	public List<Mission> getMissionList() {
		return new ArrayList<Mission>(this.missionSet);
	}

	/**
	 * @param mission
	 * 			adds a mission the missionList
	 */
	public void addMission(Mission mission) {
		this.missionSet.add(mission);
	}
	
	/**
	 * gets a proper mission for the sergeant
	 * @param sergeant is a sergeant to look a mission for.
	 * @return the i mission
	 */
	public Mission getMissionForSergeant(Sergeant sergeant) {
		String priorityOrder = sergeant.getPriorityOrder();
		Mission mission = getReadyMissionByPriority(priorityOrder, sergeant);
		return mission;
	}	
	
	/**
	 * @param priority type of the sergeant
	 * @param sergeant that would have the mission
	 * @return Mission according the priority of the sergeant
	 */
	public Mission getReadyMissionByPriority(String priority, Sergeant sergeant)
	{
		Mission m = null;
		if(priority == "shortestMission")
			m = getReadyMissionByTimePriority(true, sergeant);
		
		if(m == null & priority == "longestMission")
			m = getReadyMissionByTimePriority(false, sergeant);

		if(m == null & priority == "minItems")
			m = getReadyMissionByItemPriority(true, sergeant);
		
		if (m == null)
			m = getReadyMissionByItemPriority(false, sergeant);
		
		return serachAll(m, sergeant);
	}
	
	private Mission serachAll(Mission serchedMission, Sergeant sergeant) { // NOPMD by avikam on 12/30/11 9:41 PM
		// Restart escalation
		if (serchedMission != null) return serchedMission;
		
		Iterator<Mission> it = this.missionSet.iterator();
		Mission current;
		while(it.hasNext())
		{
			current = it.next();

			// Assure sergeant is able to perform the mission
			if (!isSergeantAssignedAndCapable(sergeant, current))
				continue;

			if(current.isActive() == false && current.getTimeLeft() > 0)
				return current;
		}
		
		return null;
	}
	
	/**
	 * 
	 * @param shortestMission - true for shortest mission, false for longest
	 * @param sergeant
	 * @return
	 */
	private Mission getReadyMissionByTimePriority(boolean shortestMission, Sergeant sergeant){
		HashMap<Integer, Mission> timeLeftMap = new HashMap<Integer, Mission>();
		Iterator<Mission> it = this.missionSet.iterator();
		Mission current;
		while(it.hasNext())
		{
			current = it.next();

			// Assure sergeant is able to perform the mission
			if (!isSergeantAssignedAndCapable(sergeant, current))
				continue;

			if(current.isActive() == false && current.getTimeLeft() > 0)
				timeLeftMap.put(current.getTimeLeft(), current);
		}
		if(timeLeftMap.size()==0)
		{
			return null;
		}
		ArrayList<Integer> times = new ArrayList<Integer>(timeLeftMap.keySet());
		Collections.sort(times);
		if(shortestMission)
			return timeLeftMap.get(times.get(0));
		else
			return timeLeftMap.get(times.get(times.size()-1));
	}

	private Mission getReadyMissionByItemPriority(boolean minItems, Sergeant sergeant){
		HashMap<Integer, Mission> itemsNeededMap = new HashMap<Integer, Mission>();
		Iterator<Mission> it = this.missionSet.iterator();
		Mission current;
		while(it.hasNext())
		{
			current = it.next();

			// Assure sergeant is able to perform the mission
			if (!isSergeantAssignedAndCapable(sergeant, current))
				continue;
			
			if(current.isActive() == false  && current.getTimeLeft() > 0)
				itemsNeededMap.put(current.getItemsRequired().size(), current);
		}
		
		if(itemsNeededMap.size()==0)
			return null;
		
		ArrayList<Integer> itemCountList = new ArrayList<Integer>(itemsNeededMap.keySet());
		Collections.sort(itemCountList);
		if(minItems)
			return itemsNeededMap.get(itemCountList.get(0));
		else
			return itemsNeededMap.get(itemCountList.get(itemCountList.size()-1));
	}
	
	/**
	 * Checks if the sergeant has a skill that is required for the mission
	 * @param s sergeant
	 * @param m mission
	 * @return true if m.skill appears on s.skills.
	 */
	private boolean isSergeantAssignedAndCapable(Sergeant s, Mission m) {
		if(m.isAssigned())
			if(m.getAssignedSergeant() != s)
				return false;
		
		return s.getSkills().indexOf(m.getRequiredSkill()) != -1;
	}
	
	/**
	 * @return the number of missions in this missionHolder.
	 */
	public int count() {
		return this.missionSet.size();
	}	
		
	/**
	 * Forgets the old mission set and create a new one
	 */
	public void resetMissionHolder() {
		this.missionSet = new HashSet<Mission>();
	}

	/**
	 * Adds new mission to the Mission holder.
	 * @param readyToExecuteMissions is a list of missions to append
	 */
	public void addMissions(List<Mission> readyToExecuteMissions) {
		this.missionSet.addAll(readyToExecuteMissions);
	}
}
